﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.CApAPPApproachDepartPlanCommand
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using DnProcessSimulateCommands.AutomaticPathPlanner;
using DnProcessSimulateCommands.AutomaticPathPlanner.Planner;
using EngineeringInternalExtension;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Tecnomatix.Engineering;


namespace DnProcessSimulateCommands;

public class CApAPPApproachDepartPlanCommand : CApAPPPlanCommandBase
{
  private System.Windows.Forms.Timer m_timer;
  private Stopwatch m_elapsedTimer;
  private long m_lastRefreshTime;
  private int m_currentNbWaypoints;
  private List<int> m_allWaypointToPlanIndexes;
  private List<int> m_subTaskToPlanIndexes;
  private List<CApAPPSegmentDepartApproachCommand> m_allThreadedPlanCommand;
  private List<Thread> m_allPlanningThreads;
  private int m_currentWaypointIndex;
  private int m_currentTaskIndex;
  private bool m_planningWasSkipped;
  private bool m_atLeastOneError;
  private double m_openingGunValue;
  private double m_perpendicularAdjustment;
  private List<List<CApAPPWaypoint>> m_originalWaypoints;

  public CApAPPApproachDepartPlanCommand(
    List<CApAPPTask> i_tasks,
    KiAppPathPlanningParamsEx i_pathPlanningParams,
    double openingGunValue,
    double perpendicularAdjustment)
    : base(i_tasks, i_pathPlanningParams)
  {
    this.m_timer = new System.Windows.Forms.Timer();
    this.m_elapsedTimer = new Stopwatch();
    this.m_lastRefreshTime = 0L;
    this.m_timer.Interval = 250;
    this.m_currentTaskIndex = 0;
    this.GetAllWayPointsToPlan(out this.m_allWaypointToPlanIndexes, out this.m_subTaskToPlanIndexes);
    this.PlanningWasCancelled = false;
    this.m_planningWasSkipped = false;
    this.m_currentWaypointIndex = -1;
    this.m_allThreadedPlanCommand = new List<CApAPPSegmentDepartApproachCommand>();
    this.m_allPlanningThreads = new List<Thread>();
    this.m_timer.Tick += new EventHandler(this.OnTimer);
    this.m_openingGunValue = openingGunValue;
    this.m_perpendicularAdjustment = perpendicularAdjustment;
    this.SaveOriginalWaypoints();
  }

  protected void SaveOriginalWaypoints()
  {
    this.m_originalWaypoints = new List<List<CApAPPWaypoint>>();
    foreach (CApAPPTask capAppTask in this.TasksToPlan)
    {
      List<CApAPPWaypoint> capAppWaypointList1 = new List<CApAPPWaypoint>();
      List<CApAPPWaypoint> capAppWaypointList2 = capAppTask.Waypoints();
      for (int index = 0; index < capAppWaypointList2.Count; ++index)
        capAppWaypointList1.Add(capAppWaypointList2[index]);
      this.m_originalWaypoints.Add(capAppWaypointList1);
    }
  }

  protected void GetAllWayPointsToPlan(
    out List<int> waypointToPlanIndexes,
    out List<int> subTaskToPlanIndexes)
  {
    waypointToPlanIndexes = new List<int>();
    subTaskToPlanIndexes = new List<int>();
    if (this.m_currentTaskIndex >= this.TasksToPlan.Count)
      return;
    this.TasksToPlan[this.m_currentTaskIndex].CountSubTasks();
    this.m_currentNbWaypoints = this.TasksToPlan[this.m_currentTaskIndex].CountWaypoints();
    for (int index = 0; index < this.TasksToPlan[this.m_currentTaskIndex].CountWaypoints(); ++index)
    {
      if (this.TasksToPlan[this.m_currentTaskIndex].Waypoint(index).Fixed && this.TasksToPlan[this.m_currentTaskIndex].GetLocation(index) is TxWeldLocationOperation)
      {
        int num = this.TasksToPlan[this.m_currentTaskIndex].RetrieveSubTaskIndexFromWaypoint(this.TasksToPlan[this.m_currentTaskIndex].Waypoint(index));
        waypointToPlanIndexes.Add(index);
        subTaskToPlanIndexes.Add(num);
      }
    }
  }

  internal CApAPPSegmentDepartApproachCommand DoCreateThreadCommand()
  {
    return new CApAPPSegmentDepartApproachCommand(this.TasksToPlan[this.m_currentTaskIndex], this.m_allWaypointToPlanIndexes[this.m_currentWaypointIndex], this.m_subTaskToPlanIndexes[this.m_currentWaypointIndex], this.m_currentNbWaypoints, this.m_openingGunValue, this.m_perpendicularAdjustment);
  }

  protected override bool DoStart(
    ref CApAPPPlanCommandBase.PlanSuccessEventArgs errEvtArgs)
  {
    bool o_trackEndReached = false;
    bool flag = this.StartNextPathPlanning(ref o_trackEndReached);
    if (!flag | o_trackEndReached)
      this.NotifyEndPlanning();
    return flag;
  }

  private CApAPPWaypoint CurrentWaypoint()
  {
    return this.TasksToPlan[this.m_currentTaskIndex].Waypoint(this.m_allWaypointToPlanIndexes[this.m_currentWaypointIndex]);
  }

  private bool UpdateWaypointsIndexes()
  {
    bool flag;
    if (this.m_currentWaypointIndex >= this.m_allWaypointToPlanIndexes.Count)
    {
      ++this.m_currentTaskIndex;
      if (this.m_currentTaskIndex < this.TasksToPlan.Count)
      {
        this.GetAllWayPointsToPlan(out this.m_allWaypointToPlanIndexes, out this.m_subTaskToPlanIndexes);
        this.m_currentWaypointIndex = 0;
        flag = true;
      }
      else
        flag = false;
    }
    else
    {
      int num1 = this.TasksToPlan[this.m_currentTaskIndex].CountWaypoints();
      flag = true;
      if (this.m_currentNbWaypoints != num1 && this.m_currentWaypointIndex < num1)
      {
        int num2 = this.TasksToPlan[this.m_currentTaskIndex].CountWaypoints() - this.m_currentNbWaypoints;
        for (int currentWaypointIndex = this.m_currentWaypointIndex; currentWaypointIndex < this.m_allWaypointToPlanIndexes.Count; ++currentWaypointIndex)
        {
          this.m_allWaypointToPlanIndexes[currentWaypointIndex] += num2;
          if (this.m_allWaypointToPlanIndexes[currentWaypointIndex] < num1)
            this.m_currentNbWaypoints = this.TasksToPlan[this.m_currentTaskIndex].CountWaypoints();
          else
            flag = false;
        }
      }
    }
    return flag;
  }

  public bool StartNextPathPlanning(ref bool o_trackEndReached)
  {
    bool flag = true;
    ++this.m_currentWaypointIndex;
    o_trackEndReached = !this.UpdateWaypointsIndexes();
    if (!o_trackEndReached)
    {
      if (this.m_currentWaypointIndex < this.m_allWaypointToPlanIndexes.Count)
      {
        flag = false;
        while (this.m_currentWaypointIndex < this.m_allWaypointToPlanIndexes.Count && !flag)
        {
          this.CurrentWaypoint();
          this.m_planningWasSkipped = false;
          this.m_allThreadedPlanCommand.Add(this.DoCreateThreadCommand());
          flag = this.m_allThreadedPlanCommand[this.m_allThreadedPlanCommand.Count - 1].StartPlanning();
          if (!flag)
            ++this.m_currentWaypointIndex;
        }
        if (flag)
        {
          this.m_timer.Start();
          this.m_elapsedTimer.Start();
          this.StartPlanningThread();
        }
        else
        {
          ++this.m_currentWaypointIndex;
          flag = true;
        }
      }
      if (this.m_currentWaypointIndex >= this.m_allWaypointToPlanIndexes.Count)
        o_trackEndReached = true;
    }
    return flag;
  }

  private void StartPlanningThread()
  {
    if (this.m_allPlanningThreads.Count > 0 && this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1] != null)
      this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1].Join();
    this.m_allPlanningThreads.Add(new Thread(new ThreadStart(this.m_allThreadedPlanCommand[this.m_allThreadedPlanCommand.Count - 1].OnStartThread)));
    this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1].Priority = ThreadPriority.Lowest;
    this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1].Start();
  }

  public override void CancelPlanning(int i_waypointRank)
  {
    this.m_planningWasSkipped = true;
    if (this.m_allThreadedPlanCommand.Count <= i_waypointRank)
      return;
    this.m_allThreadedPlanCommand[i_waypointRank].Cancel();
  }

  public override void Cancel()
  {
    this.PlanningWasCancelled = true;
    for (int index = 0; index < this.m_allThreadedPlanCommand.Count; ++index)
    {
      if (!this.m_allThreadedPlanCommand[index].IsFinished)
        this.m_allThreadedPlanCommand[index].Cancel();
    }
  }

  public override long GetElapsedTime() => this.m_elapsedTimer.ElapsedMilliseconds;

  private void OnTimer(object sender, EventArgs e)
  {
    if (this.m_elapsedTimer.ElapsedMilliseconds - this.m_lastRefreshTime > 500L)
    {
      this.UpdateProgress(sender, e);
      this.m_lastRefreshTime = this.m_elapsedTimer.ElapsedMilliseconds;
    }
    if (this.m_currentWaypointIndex >= this.m_allThreadedPlanCommand.Count || !this.m_allThreadedPlanCommand[this.m_currentWaypointIndex].IsFinished)
      return;
    if (!this.PlanningWasCancelled)
    {
      bool o_trackEndReached = false;
      this.StartNextPathPlanning(ref o_trackEndReached);
      if (!o_trackEndReached)
        return;
      this.EndPlanning(true);
    }
    else
      this.EndPlanning(true);
  }

  private void DoEndPlanning(bool i_success)
  {
    this.m_timer.Enabled = false;
    for (int index = 0; index < this.m_allPlanningThreads.Count; ++index)
    {
      if (this.m_allPlanningThreads[index].IsAlive)
        this.m_allPlanningThreads[index].Join();
    }
    for (int index = 0; index < this.TasksToPlan.Count; ++index)
    {
      this.TasksToPlan[index].CountSubTasks();
      (this.TasksToPlan[index] as CApAPPRoboticTask).UpdateApproachDepartTxOperation(this.m_originalWaypoints[index], false);
    }
    TxApplication.RefreshDisplay();
  }

  public override double GetProgress()
  {
    return (double) this.m_currentWaypointIndex / (double) this.m_allWaypointToPlanIndexes.Count;
  }

  private void EndPlanning(bool i_success)
  {
    this.DoEndPlanning(i_success);
    this.NotifyEndPlanning();
  }

  public override bool IsFinished(int i_waypointRank)
  {
    bool flag = false;
    if (i_waypointRank <= this.m_currentWaypointIndex)
      flag = this.m_allThreadedPlanCommand[i_waypointRank].IsFinished;
    return flag;
  }

  private void NotifyEndPlanning()
  {
    this.NotifyEndPlanning((object) this, new CApAPPPlanCommandBase.PlanSuccessEventArgs(this.WasPlanningProcessSuccessful(), CApAPPMainWindowStringTable.PathPlanningErrorTitle, this.ComputeErrorMessage()));
  }

  public bool WasPlanningProcessSuccessful()
  {
    return !this.m_atLeastOneError || this.PlanningWasCancelled || this.m_planningWasSkipped;
  }

  public string ComputeErrorMessage()
  {
    return $"{CApAPPMainWindowStringTable.PathPlanningErrorMsg}\r\n{CApAPPMainWindowStringTable.PathPlanningErrorCheckLocationStatusMsg}";
  }
}
